<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 
== OpenJSCAD.org, written by Rene K. Mueller <spiritdude@gmail.com>, Licensed under MIT License ==
   with some code from OpenJsCad processfile.html by Joost Nieuwenhuijse 
   in conjunction with csg.js, openjscad.js, lightgl.js by various authors (see them listed in the individual files)

Purpose: 
   More modern interface for OpenJsCad as published at http://joostn.github.com/OpenJsCad/

History:
- 2013/12/18: adapted original version of "index.html" to this smartphone/tablet enabled version 

- 2013/04/11: 0.017: alpha channel supported in color() and .setColor()
- 2013/04/07: 0.016: csg.js: solidFromSlices() and .setColor() on polygon level, and examples by Eduard Bespalov
- 2013/04/05: 0.015: rudimentary AMF export and import, web and cli
- 2013/04/03: 0.014: multiple files via drag'n'drop, developing locally
- 2013/04/01: 0.013: include() on web-online & drag'n'drop (but not off-line) and cli (server-side)
- 2013/03/20: 0.012: improved UI (slider from the left)
- 2013/03/28: 0.011: rectangular_extrude(), rotate_extrude() added, and torus()
- 2013/03/22: 0.010: leave .scad file intact, and translate on-the-fly
- 2013/03/20: 0.009: OpenSCAD .scad (via openscad-openjscad-translator) and .stl experimental import support integrated
- 2013/03/15: 0.008: minor changes, parameter window smaller, css changes
- 2013/03/14: 0.007: including jQuery to make UI changes easier, e.g. hint window moveable now
- 2013/03/11: 0.005: resize of browser fixed by fixing canvas size to full screen, and avoid scrollbars
- 2013/03/10: 0.001: first version, integrating ACE editor, for now pulled from 3rd party web-site

Todo:
- saving source code edited in ACE locally, perhaps 'SaveAs' (.JSCAD, .STL, .AMF)
- DONE: include(); support of multiple files, see http://jsfiddle.net/yybRu/
-->
<title>OpenJSCAD.org</title>
<link rel="shortcut icon" href="imgs/favicon.png" type="image/x-png">
<link rel="stylesheet" href="jquery/themes/base/jquery-ui.css" />
<script src="jquery/jquery-1.9.1.js"></script>
<script src="jquery/jquery-ui.js"></script>

<!-- MM: add support to save editor... -->
<script src='./FileSaver.js'></script>

<link rel="stylesheet" href="style_phone.css" type="text/css">
<link rel="stylesheet" href="openjscad.css" type="text/css">
</head><body onload="onload()">
<style>
/* we choose chrome theme for ace, and make sure line number is transparent too */
/* this has to stay in the body (not head) otherwise does not take effect */
.ace-chrome .ace_gutter { 
   border-left: 2px dashed rgba(200,200,200,0.2);
   background: none;
}
.ace-chrome {
   font-size: 10pt;     // -- not 'px', but 'pt' for high dpi screens
}
</style>
<script src="lightgl.js"></script>
<script src="csg.js"></script>
<script src="openjscad.js"></script>
<script src="openscad.js"></script>
<script src="underscore.js"></script>
<script src="openscad-openjscad-translator.js"></script>
<script lang=JavaScript>
var version = '0.017 (2013/12/12)';
//$(function() { $("#parametersdiv").draggable(); }); // doesn't work well, disabled
var me = document.location.toString().match(/^file:/)?'web-offline':'web-online'; // me: {cli, web-offline, web-online}
var browser = 'unknown';
if(navigator.userAgent.match(/(opera|chrome|safari|firefox|msie)/i))
   browser = RegExp.$1.toLowerCase();

$(document).ready(function() {
   $("#menu").height($(window).height());       // initial height
   $("#viewer").height($(window).height());

   $(window).resize(function() {                // adjust the relevant divs
      $("#menu").height($(window).height());
      //MM: $("#menuHandle").css({top: '45%'});
      $("#menuHandle").css({top: '30px'});
      $("#viewer").width($(window).width());
     // $("#viewer").width($(400));
      $("#viewer").height($(window).height());
   });
   //setTimeout( function(){$('#menu').css('left','-280px');},3000); // -- hide slide-menu after 3secs
   // MM: tablet menu size...
   setTimeout( function(){$('#menu').css('left','-260px');},3000); // -- hide slide-menu after 3secs

   $('#menu').mouseleave(function() {
      $('#examples').css('height',0); $('#examples').hide(); 
      $('#options').css('height',0); $('#options').hide(); 
   });

   // -- Examples
   $('#examplesTitle').click(function() {
      $('#examples').css('height','auto'); 
      $('#examples').show(); 
      $('#options').css('height',0); $('#options').hide(); 
   });
   $('#examples').mouseleave(function() {
      $('#examples').css('height',0); $('#examples').hide(); 
   });

   // -- Options 
   $('#optionsTitle').click(function() {
      $('#options').css('height','auto'); $('#options').show(); 
      $('#examples').css('height',0); $('#examples').hide(); 
   });
   $('#options').mouseleave(function() {
      $('#options').css('height',0); $('#options').hide(); 
   });
   getOptions();

   //$('#optionsForm').submit(function() {
   //   // save to cookie
   //   $('#optionsForm').hide();
   //   return false;
   //});
   $('#optionsForm').change(function() {
      // save to cookie
      saveOptions();
   });
   
   $('#plate').change(function() {
      if($('#plate').val()=='custom') {
         $('#customPlate').show();
      } else {
         $('#customPlate').hide();
      }
   });
});   
</script>
</head>
<body>

<img id="header" src="imgs/title.png">

<div id=menu>

<!-- MM: added some toggle code for touch devices...
     Fix: Some code from "mouseleave" handler..
<img id=menuHandle src="imgs/menuHandleVL.png" >
-->
<img id=menuHandle src="imgs/menuHandleVL.png" 
 onclick="if (document.getElementById('menu').className == 'visible') { document.getElementById('menu').className = ''; $('#examples').css('height',0); $('#examples').hide(); $('#options').css('height',0); $('#options').hide();  } else { document.getElementById('menu').className = 'visible'; } "
 />
<nav>
<!--
<div id=menuVersion>Version <script>document.write(version);</script></div>
<p/>
<table class=info>
<tr><td align=right class=infoOperation>Render Code</td><td class=infoKey>SHIFT + RETURN</td></tr>
<tr><td align=right class=infoOperation>Rotate XZ</td><td class=infoKey>Left Mouse</td></tr>
<tr><td align=right class=infoOperation>Pan</td><td class=infoKey>Middle Mouse or SHIFT + Left Mouse</td></tr>
<tr><td align=right class=infoOperation>Rotate XY</td><td class=infoKey>Right Mouse or ALT + Left Mouse</td></tr>
<tr><td align=right class=infoOperation>Zoom In/Out</td><td class=infoKey>Wheel Mouse or CTRL + Left Mouse</td></tr>
<tr><td align=right class=infoOperation>----------</td></tr>
<tr><td align=right class=infoOperation>Touch Device</td><td class=infoKey>(experimantal)</td></tr>
<tr><td align=right class=infoOperation>Rotate XY</td><td class=infoKey>Touch Device: 1 or 4 fingers</td></tr>
<tr><td align=right class=infoOperation>Zoom In/Out</td><td class=infoKey>Touch Device: 2 fingers pinch zoom</td></tr>
<tr><td align=right class=infoOperation>Pan</td><td class=infoKey>Touch Device: 3 fingers</td></tr>
<tr><td align=right class=infoOperation>Render Code</td><td class=infoKey>Button</td></tr>
</table>
-->


<!-- MM
<p><a class=navlink href="https://github.com/Spiritdude/OpenJSCAD.org/wiki/User-Guide" target=_blank>User Guide / Documentation <img src="imgs/externalLink.png" style=externalLink></a>
<br/><span class=menuSubInfo>How to program with OpenJSCAD: online, offline & CLI</span></p>
<p><a class=navlink href="https://plus.google.com/115007999023701819645" rel="publisher" target=_blank>Recent Updates <img src="imgs/externalLink.png" style=externalLink></a>
<br/><span class=menuSubInfo>Announcements of recent developments</span></p>
<p><a class=navlink href="https://plus.google.com/communities/114958480887231067224" target=_blank>Google+ Community <img src="imgs/externalLink.png" style=externalLink></a>
<br/><span class=menuSubInfo>Discuss with other users &amp; developers</span></p>
-->
<!--
<div id=examplesTitle class=navlink><a href='#' onclick='return false'>Examples</a></div>
<div id=examples></div>
<span class=menuSubInfo>Dozens of examples to learn from</span></p>
<p/>

-->
<!--<div id=optionsTitle class=navlink><a href='#' onclick='return false'>Options</a></div>
<div id=options>...</div>
<span class=menuSubInfo>Your personal settings</span></p>
<p/>-->

<!-- MM
<b>Supported Formats</b>
<table class=info>
<tr><td align=right><b>jscad</b></td><td><a target=_blank href="https://github.com/Spiritdude/OpenJSCAD.org/wiki/User-Guide">OpenJSCAD</a> (native, import/export)</td></tr>
<tr><td align=right><b>scad</b></td><td><a target=_blank href="http://openscad.org">OpenSCAD</a> (<a target=_blank href="https://github.com/Spiritdude/OpenJSCAD.org/wiki/User-Guide#direct-openscad-scad-import">experimental</a>, import)</td></tr>
<tr><td align=right><b>stl</b></td><td><a target=_blank href="http://en.wikipedia.org/wiki/STL_(file_format)">STL format</a> (experimental, import/export)</td></tr>
<tr><td align=right><b>amf</b></td><td><a target=_blank href="http://en.wikipedia.org/wiki/Additive_Manufacturing_File_Format">AMF format</a> (experimental, import/export)</td></tr>
</table>


<p><a class=navlink href="#" onclick="$('#about').show(); return false;">About</a></p>
-->

<textarea id="textsrc" rows="30" cols="30">
//!OpenSCAD
cube([10,10,10]);
</textarea>
<input type="button" name="Recompile" value="Compile" onclick="recompile_source();">
</nav>


</div> <!-- /menu -->

<div id=about >
<img src="imgs/title.png"><br>
Version <script>document.write(version);</script>
<p>
by Ren&eacute; K. M&uuml;ller (UI & CLI),
Joost Nieuwenhuijse (core), 
Eduard Bespalov (core),
Gary Hogdson (OpenSCAD translator)
<p>csg.js core &amp; improvements by 
Evan Wallace, 
Eduard Bespalov, 
Joost Nieuwenhuijse, 
Alexandre Girard
<p>
Licenses: MIT License &amp; GPLv2<br>
Get your copy/clone/fork from <a href="https://github.com/Spiritdude/OpenJSCAD.org" target=_blank>GitHub: OpenJSCAD</a>
<p><br>
<a class=okButton href='#' onclick="$('#about').hide(); return false;"> OK </a>
</div>


<div id="editor" >//!OpenSCAD

cube([10,10,10]);

</div>

<script>
var ex = [ 
{ file:'logo.jscad', title: 'OpenJSCAD.org Logo' },
{ file:'logo.amf', title: 'OpenJSCAD.org Logo', type: 'AMF', new: true },

{ file:'example001.jscad', title: 'Sphere with cutouts', spacing: true },
{ file:'example001.scad', title: 'Sphere with cutouts', type: 'OpenSCAD' },
{ file:'example002.jscad', title: 'Cone with cutouts' },
{ file:'example002.scad', title: 'Cone with cutouts', type: 'OpenSCAD' },
{ file:'example003.jscad', title: 'Cube with cutouts' },
{ file:'example003.scad', title: 'Cube with cutouts', type: 'OpenSCAD' },
// { file:'example004.jscad', title: 'Cube minus sphere' },
{ file:'example005.jscad', title: 'Pavillon' },
// { file:'center.jscad', title: 'Centers of Primitives' },

// { file:'bunch-cubes.jscad', title: 'Bunch of Cubes', new: true }, 
{ file:'lookup.jscad', title: 'Lookup()', spacing: true },

{ file:'name_plate.jscad', title: 'Interactive Params: Name Plate', new: true },

];
if(me=='web-online') {
   var wrap = 26;
   var colp = 100/Math.floor(ex.length/wrap+1)+"%";
   var src = '<table width=100%><tr><td widthx="+colp+" valign=top>';
   //src += "<img id=examplesHandle src=\"imgs/menuHandleHU.png\">";
   //src += '<b>Examples:</b>';
   for(var i=0; i<ex.length; i++) {
      if(ex[i].wrap) {
         src += "</td><td class=examplesSeparator widthx="+colp+" valign=top>";
      }
      if(ex[i].spacing) src += "<p/>";
      src += "<li><a href=# onclick='fetchExample(\"examples/"+ex[i].file+"\"); return false;'>"+ex[i].title+"</a>\n";
      if(ex[i].type) src += " <span class=type>("+ex[i].type+")</span></a>";
      if(ex[i].new) src += " <span class=newExample>new</span></a>";
      //src += "<li><a href='examples/"+ex[i].file+"\'>"+ex[i].title+"</a>\n";
   }
   src += "</td></tr></table>";
   $('#examples').html(src);
} else {
   // examples off-line won't work yet as XHR is used
   $('#examples').html("You are offline, drag'n'drop the examples from your installation");
}

{
   var options = [ 'renderCode', 'author', 'license' ];
   var metakeys = [ 'author', 'license' ];
   saveOptions = function() {
      for(var k in options) {
         k = options[k];
         //echo("setting "+k);
         setCookie(k,$('#'+k).val());
         if(metakeys[k]) metadata[k] = options[k];
      }
   }
   getOptions = function() {
      for(var k in options) {
         k = options[k];
         //echo("getting "+k);
         if(getCookie(k)) $('#'+k).val(getCookie(k))
      }
   }
   
   var src = '';
   src += "<form id=optionsForm onsubmit='saveOptions(); return false'>";
   src += "<div class=optionGroup><b>Your Identity / Full Name & Email</b><br/>";
   src += "<input id=author type=text name=author size=30><div class=optionInfo>Applies when you export AMF (sets metadata)</div></div>";

   var licenseOptions = {
      "Public Domain": "Public Domain", 
      "CC BY": "Creative Commons CC BY", 
      "CC BY-ND": "Creative Commons CC BY-ND", 
      "CC BY-NC": "Creative Commons CC BY-NC", 
      "CC BY-SA": "Creative Commons CC BY-SA", 
      "CC BY-NC-SA": "Creative Commons CC BY-NC-SA", 
      "CC BY-NC-ND": "Creative Commons CC BY-NC-ND", 
      "MIT": "MIT License", 
      "GPLv2": "GPLv2", 
      "GPLv3": "GPLv3", 
      "Copyright": "Copyright",
   };
   src += "<div class=optionGroup><b>Default License</b><br/>";
   src += "<select id=license name=license>";
   for(var k in licenseOptions) {
      src += "<option value='"+k+"'>"+licenseOptions[k];
      src += "<br/>";
   }
   src += "</select><div class=optionInfo>Applies when you export AMF (sets metadata)</div></div>\n";

   if(0) {
      var renderCodeOptions = {
         shiftReturn: "SHIFT+RETURN", 
         auto: "Automatic"
      };
      src += "<div class=optionGroup><b>Render Code</b></br>";
      src += "<select id=renderCode name=renderCode>";
      for(var k in renderCodeOptions) {
         src += "<option value='"+k+"'>"+renderCodeOptions[k];
      }
      src += "</select></div>";
   }
   if(1) {
      var plateOptions = {
         "200x200": "200mm x 200mm",
         "150x150": "150mm x 150mm",
         "100x100": "100mm x 100mm",
         "custom": "Custom",
         "none": "None",
      };
      src += "<div class=optionGroup><b>Plate</b></br>";
      src += "<select id=plate name=plate>";
      for(var k in plateOptions) {
         src += "<option value='"+k+"'>"+plateOptions[k];
      }
      src += "</select><br/>";
      src += "<div style='display: none' id=customPlate>Custom: <input type=text id=plateCustomX name=plateCustomX size=4 value='125'> x <input type=text id=plateCustomY name=plateCustomY size=4 value='125'> [mm]</div>";
      src += "</div>";
      
   }
   if(1) {
      var themeOptions = {
         "bright": "Bright",
         "dark": "Dark",
      };
      src += "<div class=optionGroup><b>Theme</b></br>";
      src += "<select id=theme name=theme>";
      for(var k in themeOptions) {
         src += "<option value='"+k+"'>"+themeOptions[k];
      }
      src += "</select><br/>";
      src += "</div>";
   }
   
   src += "</form>";
   $('#options').html(src);
}
</script>

<div oncontextmenu="return false;" id="viewer" ></div> <!-- avoiding popup when right mouse is clicked -->

<div id="parametersdiv" style="display:none" ></div>
<div id="tail">
<!-- MM some extra buttons for touch screen users...  -->
     <!-- MM: workaround to beautify the file-input... -->
     <input type="button" name="Recompile" value="Re-Compile" onclick="recompile_source();">
	 <!--
<input type="button" id="triggerFileOpen" name="Open" value="Open">
	<!-- 
     <input type="file", id='aceFileInput', style="display: none;", id='inputFile' />
     
            <br/>
			
    <input type='button' id='btnSave' value='Save' />	 -->    
	<!--
     <input type='button' id='btnToggle' value='Fullscreen' onclick="document.getElementById('editor').style.display = 'none';"/>
     <input type='button' id='btnToggleOn' value='Edit' onclick="document.getElementById('editor').style.display = 'block';"/>
-->
     <!-- <input type="button" name="StoreACE" value="KeepSession" onclick="store_ace();">	-->
	<!-- too dangerous to push restore instead of store :-)
	<input type="button" name="RestoreACE" value="RestoreACE" onclick="restore_ace();">    
	
     <br/>	-->		
	<!-- MM
	<input type='button' id='test' value='ToggleMenu' onclick="if (document.getElementById('menu').className == 'visible') { document.getElementById('menu').className = ''; } else { document.getElementById('menu').className = 'visible'; } ">
	-->
<!--	<a href="ii" id="DownloadLink">demo</a> -->

<!-- MM: statusdiv contains Generate button, etc. -->
<div id="statusdiv"></div>

<div id="errordiv"></div>

<!-- MM: dropzone just invisible - to ensure the code won't break somewhere else -->
<div id="filedropzone" style="display: none;">
<!-- MM: <div id="filedropzone"> -->
  <div id="filedropzone_empty">
  <script>document.write("Drop your jscad, scad, amf, stl file or multiple jscad files "+
     (browser=='chrome'&&me=='web-online'?"or folder with jscad files ":"")+
     " here (see <a style='font-weight: normal' href='https://github.com/Spiritdude/OpenJSCAD.org/wiki/User-Guide#support-of-include' target=_blank>details</a>) "+
     "<br>or edit OpenJSCAD or OpenSCAD source-code in built-in editor direct.");
  </script></div>
  <div id="filedropzone_filled">
    <span id="currentfile">...</span>
    <div id="filebuttons">
      <button id="getstlbutton" style="display:none" onclick="getStl();">Get STL</button>
      <button onclick="superviseAllFiles({forceReload:true});">Reload</button>
      <!--button onclick="parseFile(gCurrentFile,true,false);">Debug (see below)</button-->
	   <label for="autoreload">Auto Reload</label><input type="checkbox" name="autoreload" value="" id="autoreload" onclick="toggleAutoReload();">
    </div>
  </div>
</div>



<!--
<div id=footer>
OpenJSCAD.org 
<script>document.write(version);</script>, MIT License &amp; GPLv2, get your own copy/clone/fork from <a target=_blank href="https://github.com/Spiritdude/OpenJSCAD.org">GitHub: OpenJSCAD</a>
</div>
-->

</div>


<!--script src="http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script-->
<script src="ace/ace.js" type="text/javascript" charset="utf-8"></script>

<script id=conversionWorker type="javascript/worker">

// adapted from http://www.html5rocks.com/en/tutorials/workers/basics/

self.onmessage = function(e) {      // Worker to import STL/OBJ as it can take quite some while for 1MB+ large STLs
   var data = e.data; // JSON.parse(e.data);
   me = data.me;                    // required for openscad.js parse*() 
   version = data.version;          //     ''               ''

   if(data.url) {     // RANT: why do something simple, when it can be done complicate: Workers & importScripts() (guys!!)
      var url = data.url;
      url = url.replace(/#.*$/,'');    // -- just to be sure ...
      url = url.replace(/\?.*$/,'');
      var index = url.indexOf('index.html');
      if(index!=-1) {
         url = url.substring(0,index);
      }
      importScripts(url+'csg.js',url+'openjscad.js',url+'openscad.js');
      var src, type;
      data.filename.match(/\.(stl|obj|amf|gcode)$/i);
      type = RegExp.$1;
      if(type=='obj') {
         src = parseOBJ(data.source,data.filename);
      } else if(type=='amf') {
         src = parseAMF(data.source,data.filename);
      } else if(type=='gcode') {
         src = parseGCode(data.source,data.filename);
      } else {
         src = parseSTL(data.source,data.filename);
      }
      self.postMessage({ source: src, filename: data.filename, url: data.remote });
   }
};
</script>

<script>
var gCurrentFile = null;
var gProcessor = null;
var editor = null;

var gCurrentFiles = [];       // linear array, contains files (to read)
var gMemFs = [];              // associated array, contains file content in source gMemFs[i].{name,source}
var gMemFsCount = 0;          // async reading: count of already read files
var gMemFsTotal = 0;          // async reading: total files to read (Count==Total => all files read)
var gMemFsChanged = 0;        // how many files have changed
var gRootFs = [];             // root(s) of folders 

var _includePath = './';

// MM: extra code to get source recompiled on tablets :-) 
function recompile_source() {
//console.log("recompile_source()");
       
	    var asyncComputation = false;
 
            //var src = editor.getValue();
		var src =$("#textsrc").val();
			//document.getElementById("textsrc").value=src;
            if(src.match(/^\/\/\!OpenSCAD/i)) {
               editor.getSession().setMode("ace/mode/scad");
               source = openscadOpenJscadParser.parse(src);
console.log(src);			   
//console.log("recompile_source(): //!OpenSCAD identified");			   
            } else {
               editor.getSession().setMode("ace/mode/javascript");
			   source = src;
            }
            gMemFs = [];
			fn = "dummy.scad";
//console.log("recompile_source(): fn=" , fn);			   		
			//putSourceInEditor(src,fn);	
// MM: todo: seems to require the "fn" call, otherwise error situation with .scad..."			
            gProcessor.setJsCad(source,fn);
			//
            //gProcessor.setJsCad(src);
//console.log("recompile_source(): exit");			
      
}



// http://www.w3schools.com/html/html5_webstorage.asp
//  Web storage is supported in Internet Explorer 8+, Firefox, Opera, Chrome, and Safari.
//  Note: Internet Explorer 7 and earlier versions, do not support web storage.
function store_ace() {
   localStorage.jscadEditorContent= editor.getValue();
}

function restore_ace() {
  var aceContent = localStorage.getItem('jscadEditorContent');

  if(aceContent) {
     editor.setValue(aceContent); 
     editor.clearSelection();
     editor.navigateFileStart();
	 recompile_source();
  }
}




// MM: http://danielsadventure.info/HTML5FileDemo/SaxonInterface.html
        // Setup the button that the user can click to download the output.
  
  function setupFileDownload() {
  /*
    var button;
    button = document.getElementById('btnSave');
    button.addEventListener('click', function (e) {
	var outputStr, blob;
	outputStr =  editor.getSession().getValue();
	// If the string is null or empty, do nothing.
	if (!outputStr)
	    return;
	blob = new Blob([outputStr], { type: 'text/plain' });
	// Use the FileSaver.js interface to download the file.
	//saveAs(blob, 'Editor.scad');
	
//	<a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>
    });
*/
	}

/////////////////////////////////
        // MM: A small helper function that takes a file and an ACE editor object.
        // The function reads the file and copies its contents into the ACE editor.
        function putFileContentsInAceEditor(editorSource,  fn) {
						 // Code block very similar to fetchExample. TODO: reuse...
						 editor.getSession().setMode("ace/mode/javascript");
						 if(fn.match(/\.jscad$/i)||fn.match(/\.js$/i)) {
							status("Processing "+fn+" <img id=busy src='imgs/busy.gif'>");
							//if(url) editorSource = "// Remote retrieved <"+url+">\n"+editorSource;
							putSourceInEditor(editorSource,fn);
							// MM:
							source = editorSource;
							gProcessor.setJsCad(source,fn);
							
						 } else if(fn.match(/\.scad$/i)) {
							status("Converting "+fn+" <img id=busy src='imgs/busy.gif'>");
							if(!editorSource.match(/^\/\/!OpenSCAD/i)) {
							   editorSource = "//!OpenSCAD\n"+editorSource;
							}
					    	editor.getSession().setValue(editorSource);
							editor.getSession().setMode("ace/mode/scad");
							source = openscadOpenJscadParser.parse(editorSource);
                            status("Processing "+fn+" <img id=busy src='imgs/busy.gif'>");
						//	FAILS if this call is here... putSourceInEditor(editorSource,fn);						
							gProcessor.setJsCad(source,fn);							
						}			                        
            }
			
	
      // MM: Set up the HTML5 file inputs so that the user can populate the ACE editors
        // by selecting a file.
		function myLoadFileHandler(e) {
            var file;		    
			var reader, text;
			file = document.getElementById('aceFileInput').files[0]; 		
            reader = new FileReader();
            reader.onload = (function (file) {
			    fn = document.getElementById('aceFileInput').files[0].name;	
                text = file.target.result;                
				// result is loaded...							
                    // editor.getSession().setValue(text);					
				    // editorSource = 	editor.getSession().getValue();
					//console.log("myLoadFileHandler-fn", fn);
					//console.log("myLoadFileHandler-text:", text);	
				   putFileContentsInAceEditor(text, fn);
				
            });
            reader.readAsText(file);
					
		}
			
        // to establish a load handler for the Browse File button..			
        function setupFileInput() {
		// Install workaround for input-file dialog..
		$('#triggerFileOpen').on('click', function(e){
		e.preventDefault()
		$("#aceFileInput").trigger('click')
		})
	
                var aceFileInput;
                aceFileInput = document.getElementById('aceFileInput');
               // aceFileInput.addEventListener('change', myLoadFileHandler );

        }
		//////////////////////////////

	
  
//////////////////////////////////////////////////////  
  
function onload() {
   // -- http://ace.ajax.org/#nav=howto   
   
   
   //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
   document.getElementById('editor').style.display = 'none';
   
   
   
   
   editor = ace.edit("editor");
   editor.setTheme("ace/theme/chrome");
   //document.getElementById('ace_gutter').style.background = 'none';
   //MM:
  // editor.getSession().setMode("ace/mode/javascript");
   editor.getSession().setMode("ace/mode/scad");
  // src = openscadOpenJscadParser.parse(src);
				  
   editor.getSession().on('change', function(e) {
      ;
   });               
   ['Shift-Return'].forEach(function(key) {
      editor.commands.addCommand({
         name: 'myCommand',
         bindKey: { win: key, mac: key },
         exec: function(editor) {
            var src = editor.getValue();
            if(src.match(/^\/\/\!OpenSCAD/i)) {
               editor.getSession().setMode("ace/mode/scad");
               src = openscadOpenJscadParser.parse(src);
            } else {
               editor.getSession().setMode("ace/mode/javascript");
            }
            gMemFs = [];
            gProcessor.setJsCad(src);
         },
      });
   });
   if(0) {     // for reload when drag'n'dropped file(s) ([Reload] equivalent)
      viewer.onkeypress = function(evt) {
         if(evt.shiftKey&&evt.keyCode=='13') {   // Shift + Return
            superviseFiles({forceReload:true});
         }
      };
   }
   
   gProcessor = new OpenJsCad.Processor(document.getElementById("viewer"));
   setupDragDrop();

// MM: ide from: http://danielsadventure.info/HTML5FileDemo/SaxonInterface.html
setupFileInput()
setupFileDownload();
   ///////////////////////////
 /*  
   //gProcessor.setDebugging(debugging); 
   if(me=='web-online') {    // we are online, fetch first example
      //    gProcessor.setJsCad(editor.getValue());

      if(document.URL.match(/#(http:\/\/\S+)$/)||
         document.URL.match(/#(https:\/\/\S+)$/)) {   // remote file referenced, e.g. http://openjscad.org/#http://somewhere/something.ext
         var u = RegExp.$1;
         var xhr = new XMLHttpRequest();
         //echo("fetching",u);
         xhr.open("GET",'./remote.pl?url='+u,true);
         if(u.match(/\.(stl|gcode)$/i)) {
            xhr.overrideMimeType("text/plain; charset=x-user-defined");    // our pseudo binary retrieval (works with Chrome)
         }
         status("Fetching "+u+" <img id=busy src='imgs/busy.gif'>");
         xhr.onload = function() {
            //echo(this.responseText);
            var data = JSON.parse(this.responseText);
            //echo(data.url,data.filename,data.file);
            fetchExample(data.file,data.url);
            document.location = document.URL.replace(/#.*$/,'#');       // this won't reload the entire web-page
         }
         xhr.send(); 
 
      } else if(document.URL.match(/#(examples\/\S+)$/)) {    // local example, e.g. http://openjscad.org/#examples/example001.jscad
         var fn = RegExp.$1;
         fetchExample(fn);
         document.location = document.URL.replace(/#.*$/,'#');
         
      } else {
         fetchExample('examples/'+ex[0].file);
      }
   } else {
      gProcessor.setJsCad(editor.getValue());
   }
*/   
   //MM: load own demo file from root folder -> useful for tablet use...
   // edit in separate editor...
    //fetchExample('examples/'+ex[7].file);
   
   // Quick and dirty local storage persistence :-)
   restore_ace();
   //gProcessor.setJsCad(editor.getValue());
   
// fetchExample('michi.scad');
   // fetchExample('mmtest.scad');
}

function fetchExample(fn,url) {
   gMemFs = []; gCurrentFiles = [];
   
   $('#editor').show();
   
   if(fn.match(/\.[^\/]+$/)) {     // -- has extension
      ;                                  // -- we could already check if valid extension (later)
   } else {                              // -- folder referenced
      if(!fn.match(/\/$/)) 
         fn += "/";      // add tailing /
      fn += 'main.jscad';
   }

   //echo("checking gMemFs");
   //if(gMemFs[fn]) {
   //   console.log("found locally:",gMemFs[i].name);
   //}
   if(1) {     // doesn't work off-line yet
      var xhr = new XMLHttpRequest();
      xhr.open("GET", fn, true);
      if(fn.match(/\.(stl|gcode)$/i)) {
         xhr.overrideMimeType("text/plain; charset=x-user-defined");    // our pseudo binary retrieval (works with Chrome)
      }
      status("Loading "+fn+" <img id=busy src='imgs/busy.gif'>");
      xhr.onload = function() {
         var source = this.responseText;
         var editorSource = source;
         var asyncComputation = false;
         var path = fn;

         _includePath = path.replace(/\/[^\/]+$/,'/');
         
         editor.getSession().setMode("ace/mode/javascript");
         if(fn.match(/\.jscad$/i)||fn.match(/\.js$/i)) {
            status("Processing "+fn+" <img id=busy src='imgs/busy.gif'>");
            //if(url) editorSource = "// Remote retrieved <"+url+">\n"+editorSource;
            putSourceInEditor(editorSource,fn);
            gProcessor.setJsCad(source,fn);
            
         } else if(fn.match(/\.scad$/i)) {
            status("Converting "+fn+" <img id=busy src='imgs/busy.gif'>");
            editorSource = source;
            //if(url) editorSource = "// Remote retrieved <"+url+">\n"+editorSource;
            if(!editorSource.match(/^\/\/!OpenSCAD/i)) {
               editorSource = "//!OpenSCAD\n"+editorSource;
            }
            source = openscadOpenJscadParser.parse(editorSource);
            if(0) {
               source = "// OpenJSCAD.org: scad importer (openscad-openjscad-translator) '"+fn+"'\n\n"+source;
            }
            editor.getSession().setMode("ace/mode/scad");
            putSourceInEditor(editorSource,fn);
            gProcessor.setJsCad(source,fn);
            
         } else if(fn.match(/\.(stl|obj|amf|gcode)$/i)) {
            status("Converting "+fn+" <img id=busy src='imgs/busy.gif'>");
            if(!fn.match(/\.amf/)) {
               // import STL/OBJ/AMF via Worker() (async computation) as it takes quite some time
               // RANT: the whole Blob() & Worker() is anything but a clean concept, mess over mess:
               //       for example, to pass a DOM variable to worker via postMessage may create a circular reference
               //       as the data is serialized, e.g. you cannot pass document and in the Worker access document.window.
               //       Dear Google / JavaScript developers: don't make JS unuseable with this mess!
               var blobURL = new Blob([document.querySelector('#conversionWorker').textContent]);
               // -- the messy part coming here:
               //var url = window.URL; url = url.replace(/#.*$/,''); url = url.createObjectURL(blobURL);
               var worker = new Worker(window.webkitURL!==undefined?window.webkitURL.createObjectURL(blobURL):window.URL.createObjectURL(blobURL));
               //var worker = new Worker(window.URL.createObjectURL(blobURL));
               worker.onmessage = function(e) {    // worker finished
                  var data = e.data;
                  //echo("worker end:",data.source,data.filename);
                  if(e.url) data.source = "// Remote retrieve <"+e.url+">\n"+data.source;
                  putSourceInEditor(data.source,data.filename);
                  gProcessor.setJsCad(data.source,data.filename);
               };
               var u = document.location.href;
               u = u.replace(/#.*$/,'');
               u = u.replace(/\?.*$/,'');
               worker.postMessage({me: me, version: version, url: u, remote: url, source: source, filename: fn }); // start worker
               asyncComputation = true;

            } else {       // async (disabled)
               status("Converting "+fn+" <img id=busy src='imgs/busy.gif'>");
               fn.match(/\.(stl|obj|amf|gcode)$/i);
               var type = RegExp.$1;
               if(type=='obj') {
                  editorSource = source = parseOBJ(source,fn);   
               } else if(type=='amf') {
                  editorSource = source = parseAMF(source,fn);   
               } else if(type=='gcode') {
                  editorSource = source = parseGCode(source,fn);   
               } else {
                  editorSource = source = parseSTL(source,fn);   
               }
               //if(url) editorSource = source = "// Remote retrieved <"+url+">\n"+editorSource;
               putSourceInEditor(source,fn);
            }
            if(!asyncComputation) {
               gProcessor.setJsCad(source,fn);
            }
         }
      }
      xhr.send();
   }
}

function putSourceInEditor(src,fn) {
   editor.setValue(src); 
   editor.clearSelection();
   editor.navigateFileStart();

   previousFilename = fn;
   previousScript = src;
   gPreviousModificationTime = "";
}

// -----------------------------------------------------------------------------------------------------------
// Drag'n'Drop Functionality
// from old OpenJsCad processfile.html by Joost Nieuwenhuijse, 
//     with changes by Rene K. Mueller
// History:
// 2013/04/02: massively upgraded to support multiple-files (chrome & firefox) and entire directory drag'n'drop (chrome only)

// Show all exceptions to the user:
OpenJsCad.AlertUserOfUncaughtExceptions();

function setupDragDrop() {
  // Check for the various File API support.
  if (window.File && window.FileReader && window.FileList) {
    // Great success! All the File APIs are supported.
  } else {
    throw new Error("Error: Your browser does not fully support the HTML File API");
  }
  var dropZone = document.getElementById('filedropzone');
  //var dropZone = document.getElementById('viewer');
  dropZone.addEventListener('dragover', function(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy';
  }, false);
  dropZone.addEventListener('drop', handleFileSelect, false);
}

function handleFileSelect(evt) {
  evt.stopPropagation();
  evt.preventDefault();
  gMemFs = []; gMainFile = null;
  if(!evt.dataTransfer) throw new Error("Not a datatransfer (1)");
  if(!evt.dataTransfer.files) throw new Error("Not a datatransfer (2)");

  if(evt.dataTransfer.items&&evt.dataTransfer.items.length) {     // full directories, let's try
    var items = evt.dataTransfer.items;
    gCurrentFiles = [];
    gMemFsCount = 0;
    gMemFsTotal = 0;
    gMemFsChanged = 0;
    gRootFs = [];
    for(var i=0; i<items.length; i++) {
       //var item = items[i];//.webkitGetAsEntry();
       //walkFileTree({file:items[i]});
       walkFileTree(items[i].webkitGetAsEntry());
       gRootFs.push(items[i].webkitGetAsEntry());
    }
  }
  if(browser=='firefox'||me=='web-offline') {     // -- fallback, walkFileTree won't work with file://
     if(evt.dataTransfer.files.length>0) {
       gCurrentFiles = [];                              // -- be aware: gCurrentFiles = evt.dataTransfer.files won't work, as rewriting file will mess up the array
       for(var i=0; i<evt.dataTransfer.files.length; i++) {
         gCurrentFiles.push(evt.dataTransfer.files[i]);  // -- need to transfer the single elements
       }
       loadLocalFiles();
     } else {
       throw new Error("Please drop a single jscad, scad, stl file, or multiple jscad files");
     }
  }
}

function walkFileTree(item,path) {              // this is the core of the drag'n'drop:
                                                //    1) walk the tree
                                                //    2) read the files (readFileAsync)
                                                //    3) re-render if there was a change (via readFileAsync)
   path = path||"";
   //console.log("item=",item);
   if(item.isFile) {
      item.file(function(file) {                // this is also asynchronous ... (making everything complicate)
         if(file.name.match(/\.(jscad|js|scad|obj|stl|amf|gcode)$/)) {   // for now all files OpenJSCAD can handle
            console.log("walkFileTree File: "+path+item.name);
            gMemFsTotal++;
            gCurrentFiles.push(file);
            readFileAsync(file);
         }
      });

   } else if(item.isDirectory) {
      var dirReader = item.createReader();
      console.log("walkFileTree Folder: "+item.name);
      dirReader.readEntries(function(entries) {
        // console.log("===",entries,entries.length);
         for(var i=0; i<entries.length; i++) {
            //console.log(i,entries[i]);
            //walkFileTree({item:entries[i], path: path+item.name+"/"});
            walkFileTree(entries[i],path+item.name+"/");
         }
      });
   }
}

function loadLocalFiles() {               // this is the linear drag'n'drop, a list of files to read (when folders aren't supported)
  var items = gCurrentFiles;
  console.log("loadLocalFiles",items);
  gMemFsCount = 0;
  gMemFsTotal = items.length;      
  gMemFsChanged = 0;
  
  for(var i=0; i<items.length; i++) {
     var f = items[i];
     console.log(f);
     readFileAsync(f);
     //gMemFs[f.name] = f;
  }
}

function setCurrentFile(file) {              // set one file (the one dragged) or main.jscad
  gCurrentFile = file;
  gPreviousModificationTime = "";

  console.log("execute: "+file.name);
  if(file.name.match(/\.(jscad|js|scad|stl|obj|amf|gcode)$/i)) {
    gCurrentFile.lang = RegExp.$1;
  } else {
    throw new Error("Please drop a file with .jscad, .scad or .stl extension");
  }
  if(file.size == 0) {
    throw new Error("You have dropped an empty file");
  }              
  fileChanged(file);
}     

function readFileAsync(f) {                // RANT: JavaScript at its finest: 50 lines code to read a SINGLE file 
  var reader = new FileReader();           //       this code looks complicate and it is complicate.

  console.log("request: "+f.name+" ("+f.fullPath+")");
  reader.onloadend = function(evt) {
     if(evt.target.readyState == FileReader.DONE) {
        var source = evt.target.result;

        console.log("done reading: "+f.name,source?source.length:0);   // it could have been vanished while fetching (race condition)
        gMemFsCount++;
        
        if(!gMemFs[f.name]||gMemFs[f.name].source!=source)     // note: assigning f.source = source too make gMemFs[].source the same, therefore as next
          gMemFsChanged++;

        f.source = source;                 // -- do it after comparing
         
        gMemFs[f.name] = f;                // -- we cache the file (and its actual content)

        if(gMemFsCount==gMemFsTotal) {                // -- are we done reading all?
           console.log("all "+gMemFsTotal+" files read.");
           if(gMemFsTotal>1||gMemFsCount>1) {         // we deal with multiple files, so we hide the editor to avoid confusion
             $('#editor').hide();
           } else {
             $('#editor').show();
           }
           
           if(gMemFsTotal>1) {
              if(gMemFs['main.jscad']) {
                 gMainFile = gMemFs['main.jscad'];
              } else if(gMemFs['main.js']) {
                 gMainFile = gMemFs['main.js'];
              } else {
                 for(var fn in gMemFs) {
                   if(gMemFs[fn].name.match(/\/main.jscad$/)||gMemFs[fn].name.match(/\/main.js$/)) {
                      gMainFile = gMemFs[fn];
                   }
                 }
              }
           } else {
             gMainFile = f;  
           }
           if(gMemFsChanged>0) {
              if(!gMainFile)
                throw("No main.jscad found");
              console.log("update & redraw "+gMainFile.name);
              setCurrentFile(gMainFile);
           }
        }
     
     } else {
        throw new Error("Failed to read file");
        if(gProcessor) gProcessor.clearViewer();
		  previousScript = null;
     }
  };
  if(f.name.match(/\.(stl|gcode)$/)) {
     reader.readAsBinaryString(f,"UTF-8");
  } else {
     reader.readAsText(f,"UTF-8");
  }
}

function fileChanged(f) {               // update the dropzone visual & call the main parser
  var dropZone = document.getElementById('filedropzone');
  gCurrentFile = f;
  if(gCurrentFile) {
    var txt;
    if(gMemFsTotal>1) {
       txt = "Current file: "+gCurrentFile.name+" (+ "+(gMemFsTotal-1)+" more files)";
    } else {
       txt = "Current file: "+gCurrentFile.name;
    }
    document.getElementById("currentfile").innerHTML = txt;
    document.getElementById("filedropzone_filled").style.display = "block";
    document.getElementById("filedropzone_empty").style.display = "none";
  } else {
    document.getElementById("filedropzone_filled").style.display = "none";
    document.getElementById("filedropzone_empty").style.display = "block";
  }
  parseFile(f,false,false);
}

function superviseAllFiles(p) {           // check if there were changes: (re-)load all files and check if content was changed
   //var f = gMainFile;                   // note: main functionality lies in readFileAsync()
   console.log("superviseAllFiles()");
   
   gMemFsCount = gMemFsTotal = 0;
   gMemFsChanged = 0;
   
   if(p&&p.forceReload) 
      gMemFsChanged++;
   
   if(!gRootFs||me=='web-offline') {              // walkFileTree won't work with file:// (regardless of chrome|firefox)
     for(var i=0; i<gCurrentFiles.length; i++) {
        console.log("[offline] checking "+gCurrentFiles[i].name);
        gMemFsTotal++;
        readFileAsync(gCurrentFiles[i]);
      }
   } else {
      for(var i=0; i<gRootFs.length; i++) {
         walkFileTree(gRootFs[i]);
      }
   }
}

var autoReloadTimer = null;

function toggleAutoReload() {
	if (document.getElementById("autoreload").checked) {
		autoReloadTimer = setInterval(function(){
		  //parseFile(gCurrentFile,false,true);
		  superviseAllFiles();
    }, 1000);
	} else {
		if (autoReloadTimer !== null) {
			clearInterval(autoReloadTimer);
			autoReloadTimer = null;
		}
	}
}

var previousScript = null;

function parseFile(f, debugging, onlyifchanged) {     // here we convert the file to a renderable source (jscad)
  if(arguments.length==2) {
    debugging = arguments[1];
    onlyifchanged = arguments[2];
    f = gCurrentFile;
  }
  //gCurrentFile = f;
  var source = f.source;
  var editorSource = source;
  if(source == "") {
    if(document.location.toString().match(/^file\:\//i)) {
      throw new Error("Could not read file. You are using a local copy of OpenJSCAD.org; if you are using Chrome, you need to launch it with the following command line option:\n\n--allow-file-access-from-files\n\notherwise the browser will not have access to uploaded files due to security restrictions.");
    } else {
      throw new Error("Could not read file.");
    }            
  } else {         
    if(gProcessor && ((!onlyifchanged) || (previousScript !== source))) {
      var fn = gCurrentFile.name;
      fn = fn.replace(/^.*\/([^\/]*)$/,"$1");     // remove path, leave filename itself
      gProcessor.setDebugging(debugging); 
      //echo(gCurrentFile.lang);
      editor.getSession().setMode("ace/mode/javascript");
      var asyncComputation = false;
      
      if(gCurrentFile.lang=='jscad'||gCurrentFile.lang=='js') {
         ; // default
      } else if(gCurrentFile.lang=='scad') {
         editorSource = source;
         if(!editorSource.match(/^\/\/!OpenSCAD/i)) {
            editorSource = "//!OpenSCAD\n"+editorSource;
         }
         source = openscadOpenJscadParser.parse(editorSource);
         if(0) {
            source = "// OpenJSCAD.org: scad importer (openscad-openjscad-translator) '"+fn+"'\n\n"+source;
         }
         editor.getSession().setMode("ace/mode/scad");  
         
      } else if(gCurrentFile.lang.match(/(stl|obj|amf|gcode)/i)) {
         status("Converting "+fn+" <img id=busy src='imgs/busy.gif'>");
         if(!fn.match(/amf/i)) {     // -- if you debug the STL parsing, change it to 'if(0&&...' so echo() works, otherwise in workers
                                     //    echo() is not working.., and parseAMF requires jquery, which seem not working in workers
            var blobURL = new Blob([document.querySelector('#conversionWorker').textContent]);
            // -- the messy part coming here:
            var worker = new Worker(window.webkitURL!==undefined?window.webkitURL.createObjectURL(blobURL):window.URL.createObjectURL(blobURL));
            worker.onmessage = function(e) {
               var data = e.data;
               //echo("finished converting, source:",data.source);
               if(data&&data.source&&data.source.length) {              // end of async conversion
                  putSourceInEditor(data.source,data.filename);
                  gMemFs[data.filename].source = data.source;
                  gProcessor.setJsCad(data.source,data.filename);
               } else {
                  // worker responds gibberish (likely echo(), but format unknown)
                  // echo("STL worker",data);
               }
            };
            var u = document.location.href;
            u = u.replace(/#.*$/,'');
            u = u.replace(/\?.*$/,'');
            worker.postMessage({me: me, version: version, url: u, source: source, filename: fn });
            asyncComputation = true;
         } else {
            fn.match(/\.(stl|obj|amf|gcode)$/i);
            var type = RegExp.$1;
            if(type=='obj') {
               editorSource = source = parseOBJ(source,fn);   
            } else if(type=='amf') {
               editorSource = source = parseAMF(source,fn);   
            } else if(type=='gcode') {
               editorSource = source = parseGCode(source,fn);   
            } else {
               editorSource = source = parseSTL(source,fn);   
            }
         }
      } else {
         throw new Error("Please drop a file with .jscad, .scad or .stl extension");
      }
      if(!asyncComputation) {                   // end of synchronous conversion
         putSourceInEditor(editorSource,fn);
         gMemFs[fn].source = source;
         gProcessor.setJsCad(source,fn);
      }
    }
  }
}

// ---------------------------------------------------------------------------------------------------------

function setCookie(name, value, days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = "; expires=" + date.toGMTString();
    } else var expires = "";
    document.cookie = escape(name) + "=" + escape(value) + expires + "; path=/";
}

function getCookie(name) {
    var nameEQ = escape(name) + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length, c.length));
    }
    return null;
}

function deleteCookie(name) {
    createCookie(name, "", -1);
}



</script>
</body></html> 
